import 'dart:io';

import 'package:archive/archive.dart';
import 'package:cosmic_resource_downloader/utils.dart';
import 'package:path/path.dart' as p;
import 'package:xml/xml.dart' as xml;

import 'cli.dart';
import 'tui.dart';

class Unzipper {
  final CliOptions options;
  final TUI tui;
  final String envNumber;

  Unzipper(this.options, this.tui, this.envNumber);

  Future<void> execute() async {
    if (options.dryRun) {
      tui.log('✅ Dry run: Skipping unzip phase.');
      return;
    }

    tui.log('');
    tui.log('=== Starting Unzip Phase ===');

    // Clean target directories
    await cleanDirectory(p.join(options.dir, 'mservice-cosmic', 'lib'));
    await cleanDirectory(p.join(options.dir, 'static-file-service'));

    // Unzip webapp files
    final webappDir = p.join(options.dir, 'webapp');
    if (await Directory(webappDir).exists()) {
      final webappFiles = await Directory(webappDir)
          .list()
          .where((f) => p.extension(f.path).endsWith(".zip"))
          .toList();
      for (final file in webappFiles) {
        // tui.updateTask('Unzipping ${p.basename(file.path)}', 0);
        tui.log('📦 Unzipping webapp: ${p.basename(file.path)}');
        await _unzipTo(file.path, p.join(options.dir, 'static-file-service'));
      }
    }

    // Unzip appstore files
    final appstoreDir = p.join(options.dir, 'appstore');
    if (await Directory(appstoreDir).exists()) {
      // biz, trd, cus
      final subdirs = ['bos', 'biz', 'trd', 'cus'];
      for (final subdir in subdirs) {
        final dirPath = p.join(appstoreDir, subdir);
        if (await Directory(dirPath).exists()) {
          var xmlFiles = await Directory(dirPath)
          .list()
          .where((f) => p.extension(f.path) == '.xml')
          .toList();

          var allowedFiles = await readXmls(xmlFiles);

          final zipFiles = await Directory(dirPath)
              .list()
              .where((f) => p.extension(f.path) == '.zip'
                        && allowedFiles.contains(p.basenameWithoutExtension(f.path)))
              .toList();
          for (final file in zipFiles) {
            // tui.updateTask('Unzipping ${p.basename(file.path)}', 0);
            tui.log('📦 Unzipping appstore/$subdir: ${p.basename(file.path)}');
            final targetDir =
                p.join(options.dir, 'mservice-cosmic', 'lib', subdir);
            await _unzipTo(file.path, targetDir);
          }
        }
      }
    }

    // tui.updateTask('All unzips completed', 100);
    tui.log('✅ All files unzipped successfully.');
  }

  Future<List<String>> readXmls(List<FileSystemEntity> xmlFiles) async{
    List<String> result = [];
    for (var file in xmlFiles) {
      var doc = xml.XmlDocument.parse(await File(file.path).readAsString());
      var list = doc.findAllElements('zip')
          .map((element) => element.innerText.trim())
          .toList();

      result.addAll(list);
    }

    return result;
  }

  Future<void> _unzipTo(String zipPath, String targetDir) async {
    await ensureDirectoryExists(targetDir);

    final bytes = await File(zipPath).readAsBytes();
    final archive = ZipDecoder().decodeBytes(bytes);

    for (final file in archive) {
      final filename = file.name;
      final filePath = p.join(targetDir, filename);

      if (file.isFile) {
        await ensureDirectoryExists(p.dirname(filePath));
        final outFile = File(filePath);
        await outFile.create(recursive: true);
        await outFile.writeAsBytes(file.content as List<int>);
      } else {
        await ensureDirectoryExists(filePath);
      }
    }
  }
}
